package com.sohu.tv.mq.cloud.task.server.data;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.lang3.math.NumberUtils;

/**
 * io读写情况
 * 
 * @Description:
 * @author yongfeigao
 * @date 2018年7月18日
 */
public class Disk implements LineParser {
    public static final String FLAG = "DISK";
    public static final Pattern PATTERN = Pattern.compile("^BBBP,[0-9]+,/bin/df-m,");
    public static final Pattern SUBPARTITION_PATTERN = Pattern.compile("[0-9]+$");
    // 包括总的状况及各个分区的状况
    private Map<DiskUsageType, List<Usage>> diskMap = new HashMap<Disk.DiskUsageType, List<Usage>>();

    /**
     * line format: DISKBUSY,Disk %Busy iZ256oe4w5bZ,xvda,xvda1,xvdb,xvdb1
     * DISKREAD,Disk Read KB/s iZ256oe4w5bZ,xvda,xvda1,xvdb,xvdb1 DISKWRITE,Disk
     * Write KB/s iZ256oe4w5bZ,xvda,xvda1,xvdb,xvdb1 DISKXFER,Disk transfers per
     * second iZ256oe4w5bZ,xvda,xvda1,xvdb,xvdb1 DISKBSIZE,Disk Block Size
     * iZ256oe4w5bZ,xvda,xvda1,xvdb,xvdb1 DISKBUSY,T0001,0.0,0.0,0.0,0.0
     * DISKREAD,T0001,0.0,0.0,0.0,0.0 DISKWRITE,T0001,0.0,0.0,0.0,0.0
     * DISKXFER,T0001,0.0,0.0,0.0,0.0 DISKBSIZE,T0001,0.0,0.0,0.0,0.0
     * BBBP,173,/bin/df-m,"ddev/xvda1 20158 16018 3117 84% /"
     */
    public void parse(String line, String timeKey) throws Exception {
        if (line.startsWith(FLAG)) {
            String[] items = line.split(",");
            if (!items[1].equals(timeKey)) {
                DiskUsageType type = DiskUsageType.getType(items[0]);
                if (type == null) {
                    return;
                }
                List<Usage> list = diskMap.get(type);
                if (list == null) {
                    list = new ArrayList<Usage>();
                    diskMap.put(type, list);
                }
                for (int i = 2; i < items.length; ++i) {
                    Usage usage = new Usage();
                    usage.setDiskUsageTyp(type);
                    usage.setName(items[i]);
                    list.add(usage);
                }
            } else {
                DiskUsageType type = DiskUsageType.getType(items[0]);
                if (type == null) {
                    return;
                }
                List<Usage> list = diskMap.get(type);
                if (list == null) {
                    return;
                }
                for (int i = 2; i < items.length; ++i) {
                    float value = NumberUtils.toFloat(items[i]);
                    if (value > 0) {
                        list.get(i - 2).setValue(value);
                    }
                }
            }
        } else if (PATTERN.matcher(line).find()) {
            String[] tmp = line.split(",\"");
            if (tmp.length > 0) {
                String[] item = tmp[tmp.length - 1].split("\\s+");
                if (item.length != 6 || !item[4].contains("%")) {
                    return;
                }
                List<Usage> list = diskMap.get(DiskUsageType.busy);
                String[] tp = item[0].split("/");
                String mount = tp[tp.length - 1];
                for (Usage usage : list) {
                    if (usage.getName().equals(mount)) {
                        List<Usage> spaceList = diskMap.get(DiskUsageType.space);
                        if (spaceList == null) {
                            spaceList = new ArrayList<Usage>();
                            diskMap.put(DiskUsageType.space, spaceList);
                        }
                        Usage spaceUsage = new Usage();
                        spaceUsage.setDiskUsageTyp(DiskUsageType.space);
                        spaceUsage.setName(usage.getName());
                        spaceUsage.setValue(NumberUtils.toFloat(item[4].split("%")[0]));
                        spaceList.add(spaceUsage);
                    }
                }
            }
        }
    }

    public Map<DiskUsageType, List<Usage>> getDiskMap() {
        return diskMap;
    }

    public float getRead() {
        List<Usage> usageList = diskMap.get(DiskUsageType.read);
        return getUsage(usageList);
    }

    public float getWrite() {
        List<Usage> usageList = diskMap.get(DiskUsageType.write);
        return getUsage(usageList);
    }

    public float getIops() {
        List<Usage> usageList = diskMap.get(DiskUsageType.transfer);
        return getUsage(usageList);
    }

    public float getBusy() {
        List<Usage> usageList = diskMap.get(DiskUsageType.busy);
        return getUsage(usageList);
    }

    public String getExt() {
        StringBuilder sb = new StringBuilder();
        for (DiskUsageType type : diskMap.keySet()) {
            if (DiskUsageType.space == type) {
                continue;
            }
            sb.append(type.getValue());
            sb.append("=");
            List<Usage> usageList = diskMap.get(type);
            for (Usage use : usageList) {
                sb.append(use.getName());
                sb.append(":");
                sb.append(use.getValue());
                sb.append(",");
            }
            sb.append(";");
        }
        return sb.toString();
    }

    public String getSpace() {
        StringBuilder sb = new StringBuilder();
        List<Usage> usageList = diskMap.get(DiskUsageType.space);
        if (usageList == null) {
            return sb.toString();
        }
        for (Usage use : usageList) {
            sb.append(use.getName());
            sb.append(":");
            sb.append(use.getValue());
            sb.append(",");
        }
        return sb.toString();
    }

    private float getUsage(List<Usage> usageList) {
        float usage = 0;
        if (usageList != null) {
            for (Usage u : usageList) {
                if (!SUBPARTITION_PATTERN.matcher(u.getName()).find()) {
                    usage += u.getValue();
                }
            }
        }
        return usage;
    }

    @Override
    public String toString() {
        return "Disk [diskMap=" + diskMap + "]";
    }

    /**
     * 使用率
     */
    class Usage {
        // 分区名字
        private String name;
        // 使用率类型
        private DiskUsageType diskUsageType;
        // 使用率
        private float value;

        public DiskUsageType getDiskUsageType() {
            return diskUsageType;
        }

        public void setDiskUsageTyp(DiskUsageType diskUsageType) {
            this.diskUsageType = diskUsageType;
        }

        public float getValue() {
            return value;
        }

        public void setValue(float value) {
            this.value = value;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Usage [name=" + name + ", diskUsageType=" + diskUsageType
                    + ", value=" + value + "]";
        }
    }

    /**
     * 使用率类型
     */
    enum DiskUsageType {
        // 繁忙程度
        busy("DISKBUSY"),
        // 读
        read("DISKREAD"),
        // 写
        write("DISKWRITE"),
        // io次数
        transfer("DISKXFER"),
        // 空间使用率
        space("df"),
        ;
        private String value;

        private DiskUsageType(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public static DiskUsageType getType(String type) {
            for (DiskUsageType dut : DiskUsageType.values()) {
                if (dut.getValue().equals(type)) {
                    return dut;
                }
            }
            return null;
        }
    }
}
